//* ////////////////////////////////////////////////////////////////////////////// */
//*
//
//              INTEL CORPORATION PROPRIETARY INFORMATION
//  This software is supplied under the terms of a license  agreement or
//  nondisclosure agreement with Intel Corporation and may not be copied
//  or disclosed except in  accordance  with the terms of that agreement.
//        Copyright (c) 2010 - 2013 Intel Corporation. All Rights Reserved.
//
//
//*/


#include <windows.h>
#include <psapi.h>
#include <d3d9.h>
#include "d3d_allocator.h"
#include "d3d11_allocator.h"
#include "sysmem_allocator.h"
#include "transcode_utils.h"

using namespace TranscodingSample;

// parsing defines
#define IS_SEPARATOR(ch)  ((ch) <= ' ' || (ch) == '=')
#define VAL_CHECK(val, argIdx, argName) {\
    if (val) \
    {\
        PrintHelp(NULL, MSDK_STRING("Input argument number %d \"%s\" require more parameters"), argIdx, argName); \
        return MFX_ERR_UNSUPPORTED;\
    }}

mfxU64 TranscodingSample::GetTick()
{
    LARGE_INTEGER tick;
    QueryPerformanceCounter(&tick);
    return tick.QuadPart;
}

mfxF64 TranscodingSample::GetTime(mfxU64 start)
{
    LARGE_INTEGER freq;
    QueryPerformanceFrequency(&freq);

    LARGE_INTEGER tick;
    QueryPerformanceCounter(&tick);
    return (mfxF64)((tick.QuadPart - start)/(mfxF64)freq.QuadPart);
}
void TranscodingSample::PrintHelp(msdk_char *strAppName, msdk_char *strErrorMessage, ...)
{
    msdk_printf(MSDK_STRING("Intel(R) Media SDK Multi Transcoding Sample Version %s\n\n"), MSDK_SAMPLE_VERSION);

    if (strErrorMessage)
    {
        va_list args;
        msdk_printf(MSDK_STRING("ERROR: "));
        va_start(args, strErrorMessage);
        msdk_vprintf(strErrorMessage, args);
        va_end(args);
        msdk_printf(MSDK_STRING("\n\n"));
    }
    
    msdk_printf(MSDK_STRING("Command line parameters\n"));
    
    if (strAppName)
        msdk_printf(MSDK_STRING("Usage: %s -par ParFile [-p PerfStatFile] \n"), strAppName);
    msdk_printf(MSDK_STRING("\
    Information on ParFile format can be found in readme-multi-transcode.rtf\n\
\n\
    If the only transcoding session is needed the following usage is acceptable\n"));
    if (strAppName)
        msdk_printf(MSDK_STRING("Usage: %s -i::h264|mpeg2|vc1|mvc|jpeg InputCodedBSFile -o::h264|mpeg2|mvc|jpeg OutputEncodedFile -w width -h height [options]\n"), strAppName);
    msdk_printf(MSDK_STRING("\
Where [options] can be: \n\
    [-f frameRate] - video frame rate for the whole pipeline (frames per second), overwrites input stream's framerate is taken\n\
    [-b bitRate] - encoded bit rate (Kbits per second), valid for H.264, MPEG2 and MVC encoders\n\
    [-u 1|4|7] - target usage: quality (1), balanced (4) or speed (7); valid for H.264, MPEG2 and MVC encoders. Default is balanced\n\
    [-q quality] - quality parameter for JPEG encoder; in range [1,100], 100 is the best quality \n\
    [-l numSlices] - number of slices for encoder; default value 0 \n\
    [-w] - destination picture width, invokes VPP resizing\n\
    [-h] - destination picture height, invokes VPP resizing\n\
    [-async] - depth of asynchronous pipeline. default value 1\n\
    [-sw|-hw|-hw_d3d11] - SDK implementation to use: \n\t-hw - platform-specific on default display adapter,\n\t-hw_d3d11 - platform-specific via d3d11\n\t-sw - software (default). \n\
    [-join] - join session with other session(s), by default sessions are not joined\n\
    [-priority] - use priority for join sessions. 0 - Low, 1 - Normal, 2 - High. Normal by default\n\
    [-n ] - Number of frames to transcode \n\
    [-angle 180] - enables 180 degrees picture rotation user module before encoding\n\
    [-opencl] - uses implementation of rotation plugin (enabled with -angle option) through Intel(R) OpenCL\n\
    [-deinterlace] - forces VPP to deinterlace input stream\n\
\n\
    Example: -i::mpeg2 in.mpeg2 -o::h264 out.h264\n\
    Example: -i::mvc in.mvc -o::mvc out.mvc -w 320 -h 240\n"));
}

void TranscodingSample::PrintInfo(mfxU32 session_number, sInputParams* pParams, mfxVersion *pVer)
{
    msdk_char buf[2048];
    MSDK_CHECK_POINTER_NO_RET(pVer);    
    
    if ((MFX_IMPL_AUTO <= pParams->libType) && (MFX_IMPL_HARDWARE4 >= pParams->libType))
    {
        msdk_printf(MSDK_STRING("MFX %s Session %d API ver %d.%d parameters: \n"),
            (MFX_IMPL_SOFTWARE == pParams->libType)? MSDK_STRING("SOFTWARE") : MSDK_STRING("HARDWARE"),
                 session_number,
                 pVer->Major,
                 pVer->Minor);
    }

    if (0 == pParams->DecodeId)
        msdk_printf(MSDK_STRING("Input  video: From parent session\n"));
    else
        msdk_printf(MSDK_STRING("Input  video: %s\n"), CodecIdToStr(pParams->DecodeId).c_str());

    // means that source is parent session
    if (0 == pParams->EncodeId)
        msdk_printf(MSDK_STRING("Output video: To child session\n"));
    else
        msdk_printf(MSDK_STRING("Output video: %s\n"), CodecIdToStr(pParams->EncodeId).c_str());
    if (PrintDllInfo(buf, ARRAYSIZE(buf), pParams))
        msdk_printf(MSDK_STRING("MFX dll: %s\n"),buf);
    msdk_printf(MSDK_STRING("\n"));
}

bool TranscodingSample::PrintDllInfo(msdk_char* buf, mfxU32 buf_size, sInputParams* pParams)
{
    HANDLE   hCurrent = GetCurrentProcess();
    HMODULE *pModules;
    DWORD    cbNeeded;
    int      nModules;
    if (NULL == EnumProcessModules(hCurrent, NULL, 0, &cbNeeded))
        return false;

    nModules = cbNeeded / sizeof(HMODULE);

    pModules = new HMODULE[nModules];
    if (NULL == pModules)
    {
        return false;
    }
    if (NULL == EnumProcessModules(hCurrent, pModules, cbNeeded, &cbNeeded))
    {
        delete []pModules;
        return false;
    }

    for (int i = 0; i < nModules; i++)
    {
        GetModuleFileName(pModules[i], buf, buf_size);
        if (_tcsstr(buf, MSDK_STRING("libmfxhw")) && (MFX_IMPL_SOFTWARE != pParams->libType))
        {
            delete []pModules;
            return true;
        }
        else if (_tcsstr(buf, MSDK_STRING("libmfxsw")) && (MFX_IMPL_SOFTWARE == pParams->libType))
        {
            delete []pModules;
            return true;
        }

    }
    delete []pModules;
    return false;
}

CmdProcessor::CmdProcessor()
{
    m_SessionParamId = 0;
    m_SessionArray.clear();
    m_PerfFILE = NULL;
    m_parName = NULL;

} //CmdProcessor::CmdProcessor()

CmdProcessor::~CmdProcessor()
{
    m_SessionArray.clear();
    if (m_PerfFILE)
        fclose(m_PerfFILE);

} //CmdProcessor::~CmdProcessor()

void CmdProcessor::PrintParFileName()
{
    if (m_parName && m_PerfFILE)
    {
        msdk_fprintf(m_PerfFILE, MSDK_STRING("Input par file: %s\n\n"), m_parName);
    }
}

mfxStatus CmdProcessor::ParseCmdLine(int argc, msdk_char *argv[])
{
    FILE *parFile = NULL;
    mfxStatus sts = MFX_ERR_UNSUPPORTED;
      
    if (1 == argc)
    {
       PrintHelp(argv[0], NULL);
       return MFX_ERR_UNSUPPORTED;
    }

    // parse command line
    for (mfxU8 i = 1; i < argc; i++)
    {
        if (0 == msdk_strcmp(argv[i], MSDK_STRING("-par")))
        {
            if (parFile)
            {
                PrintHelp(argv[0], MSDK_STRING("Only one par file is supported"));
                return MFX_ERR_UNSUPPORTED;
            }
            i++;
            m_parName = argv[i];
        }
        else if (0 == msdk_strcmp(argv[i], MSDK_STRING("-?")) )
        {
            PrintHelp(argv[0], NULL);
            return MFX_ERR_UNSUPPORTED;
        }
        else if (0 == msdk_strcmp(argv[i], MSDK_STRING("-p")))
        {
            if (m_PerfFILE)
            {
                PrintHelp(argv[0], MSDK_STRING("Only one performance file is supported"));
                return MFX_ERR_UNSUPPORTED;
            }
            i++;
            MSDK_FOPEN(m_PerfFILE, argv[i],MSDK_STRING("w"));
            if (NULL == m_PerfFILE)
            {
                PrintHelp(argv[0], MSDK_STRING("performance file \"%s\" not found"), argv[i]);
                return MFX_ERR_UNSUPPORTED;
            }
        }
    }

    if (NULL != m_parName)
    {
        MSDK_FOPEN(parFile, m_parName, MSDK_STRING("r"));
        if (NULL == parFile)
        {
            PrintHelp(argv[0], MSDK_STRING("ParFile \"%s\" not found"), m_parName);
            return MFX_ERR_UNSUPPORTED;
        }
    }
    msdk_printf(MSDK_STRING("Intel(R) Media SDK Multi Transcoding Sample Version %s\n\n"), MSDK_SAMPLE_VERSION);
    msdk_printf(MSDK_STRING("Par file is: %s\n\n"), m_parName);
    sts = _ParseParamsForOneSession(argc-1, argv+1);
    if (MFX_ERR_NONE != sts)
    {
        if (NULL != parFile)
        {
            fclose(parFile);
            parFile = NULL;
        }
        return sts;
    }
    
    if (NULL != m_parName)
    {
        sts = ParseParFile(parFile);
        if (MFX_ERR_NONE != sts)
        {
            PrintHelp(argv[0], MSDK_STRING("Command line is invalid"));
            if (NULL != parFile)
            {
                fclose(parFile);
                parFile = NULL;
            }
            return sts;
        }

        fclose(parFile);
    }

    return sts;

} //mfxStatus CmdProcessor::ParseCmdLine(int argc, msdk_char *argv[])

mfxStatus CmdProcessor::ParseParFile(FILE *parFile)
{
    mfxStatus sts = MFX_ERR_UNSUPPORTED;
    if (!parFile)
        return MFX_ERR_UNSUPPORTED;

    mfxU32 currPos = 0;
    mfxU32 lineIndex = 0;

    // calculate file size
    fseek(parFile, 0, SEEK_END);
    mfxU32 fileSize = ftell(parFile) + 1;
    fseek(parFile, 0, SEEK_SET);

    // allocate buffer for parsing
    s_ptr<msdk_char, false> parBuf;
    parBuf.reset(new msdk_char[fileSize]);
    msdk_char *pCur;

    while(currPos < fileSize)
    {
        pCur = /*_fgetts*/msdk_fgets(parBuf.get(), fileSize, parFile);
        if (!pCur)
            return MFX_ERR_NONE;
        while(pCur[currPos] != '\n' && pCur[currPos] != 0)
        {
            currPos++;
            if  (pCur + currPos >= parBuf.get() + fileSize)
                return sts;
        }
        // zero string
        if (!currPos)
            continue;

        sts = ParseParamsForOneSession(pCur, currPos);
        if (MFX_ERR_NONE != sts)
            PrintHelp(NULL, MSDK_STRING("Error in par file parameters at line %d"), lineIndex);
        MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
        currPos = 0;
        lineIndex++;
    }
    
    return MFX_ERR_NONE;

} //mfxStatus CmdProcessor::ParseParFile(FILE *parFile)

mfxStatus CmdProcessor::ParseParamsForOneSession(msdk_char *pLine, mfxU32 length)
{
    mfxU32 i;
    const mfxU8 maxArgNum = 255;
    msdk_char *argv[maxArgNum+1];
    mfxU32 argc = 0;
    s_ptr<msdk_char, false> pMemLine;

    pMemLine.reset(new msdk_char[length+2]);

    msdk_char *pTempLine = pMemLine.get();
    pTempLine[0] = ' ';
    pTempLine++;

    MSDK_MEMCPY_BUF(pTempLine,0 , length*sizeof(msdk_char), pLine, length*sizeof(msdk_char));

    // parse into command streams
    for (i = 0; i < length ; i++)
    {
        // check if separator
        if (IS_SEPARATOR(pTempLine[-1]) && !IS_SEPARATOR(pTempLine[0]))
        {       
            argv[argc++] = pTempLine;            
            if (argc > maxArgNum)
            {
                PrintHelp(NULL, MSDK_STRING("Too many parameters (reached maximum of %d)"), maxArgNum);
                return MFX_ERR_UNSUPPORTED;
            }
        }
        if (pTempLine[0] == ' ')
        {
            pTempLine[0] = 0;
        }
        pTempLine++;
    }   

    // EOL for last parameter
    pTempLine[0] = 0;

    return _ParseParamsForOneSession(argc, argv);
}

mfxStatus CmdProcessor::_ParseParamsForOneSession(mfxU32 argc, msdk_char *argv[])
{
    mfxStatus sts;
    mfxU32 i;
    mfxU32 skipped = 0;
    TranscodingSample::sInputParams InputParams;   
    msdk_char endC;

    for (i = 0; i < argc; i++)
    {
        // process multi-character options
        if (0 == msdk_strcmp(argv[i], MSDK_STRING("-i::mpeg2")))
        {
            // only encode supports
            if (InputParams.eMode == Source)
                return MFX_ERR_UNSUPPORTED;

            VAL_CHECK(i+1 == argc, i, argv[i]);
            i++;
            msdk_strcopy(InputParams.strSrcFile, argv[i]);      
            InputParams.DecodeId = MFX_CODEC_MPEG2;
        }
        else if (0 == msdk_strcmp(argv[i], MSDK_STRING("-i::h264")))
        {
            // only encode supports
            if (InputParams.eMode == Source)
                return MFX_ERR_UNSUPPORTED;

            VAL_CHECK(i+1 == argc, i, argv[i]);
            i++;
            msdk_strcopy(InputParams.strSrcFile, argv[i]);
            InputParams.DecodeId = MFX_CODEC_AVC;
        }
        else if (0 == msdk_strcmp(argv[i], MSDK_STRING("-i::vc1")))
        {
            // only encode supports
            if (InputParams.eMode == Source)
                return MFX_ERR_UNSUPPORTED;

            VAL_CHECK(i+1 == argc, i, argv[i]);
            i++;
            msdk_strcopy(InputParams.strSrcFile, argv[i]);
            InputParams.DecodeId = MFX_CODEC_VC1;
        }
        else if (0 == msdk_strcmp(argv[i], MSDK_STRING("-i::mvc")))
        {
            // only encode supports
            if (InputParams.eMode == Source)
                return MFX_ERR_UNSUPPORTED;

            VAL_CHECK(i+1 == argc, i, argv[i]);
            i++;
            msdk_strcopy(InputParams.strSrcFile, argv[i]);
            InputParams.DecodeId = MFX_CODEC_AVC;
            InputParams.bIsMVC = true;
        }
        else if (0 == msdk_strcmp(argv[i], MSDK_STRING("-i::jpeg")))
        {
            // only encode supports
            if (InputParams.eMode == Source)
                return MFX_ERR_UNSUPPORTED;

            VAL_CHECK(i+1 == argc, i, argv[i]);
            i++;
            msdk_strcopy(InputParams.strSrcFile, argv[i]);
            InputParams.DecodeId = MFX_CODEC_JPEG;            
        }
        else if (0 == msdk_strcmp(argv[i], MSDK_STRING("-o::mpeg2")))
        {
            // only decode supports
            if (InputParams.eMode == Sink)
                return MFX_ERR_UNSUPPORTED;

            // In case of MVC only MVC-MVC transcoding is supported
            if (InputParams.bIsMVC)
                return MFX_ERR_UNSUPPORTED;

            VAL_CHECK(i+1 == argc, i, argv[i]);
            i++;
            msdk_strcopy(InputParams.strDstFile, argv[i]);
            InputParams.EncodeId = MFX_CODEC_MPEG2;
        }
        else if (0 == msdk_strcmp(argv[i], MSDK_STRING("-o::h264")))
        {
            // only decode supports
            if (InputParams.eMode == Sink)
                return MFX_ERR_UNSUPPORTED;

            // In case of MVC only MVC-MVC transcoding is supported
            if (InputParams.bIsMVC)
                return MFX_ERR_UNSUPPORTED;

            VAL_CHECK(i+1 == argc, i, argv[i]);
            i++;
            msdk_strcopy(InputParams.strDstFile, argv[i]);
            InputParams.EncodeId = MFX_CODEC_AVC;
        }
        else if (0 == msdk_strcmp(argv[i], MSDK_STRING("-o::mvc")))
        {
            // only decode supports
            if (InputParams.eMode == Sink)
                return MFX_ERR_UNSUPPORTED;            

            VAL_CHECK(i+1 == argc, i, argv[i]);
            i++;
            msdk_strcopy(InputParams.strDstFile, argv[i]);
            InputParams.EncodeId = MFX_CODEC_AVC;
            InputParams.bIsMVC = true;
        }
        else if (0 == msdk_strcmp(argv[i], MSDK_STRING("-o::jpeg")))
        {
            // only decode supports
            if (InputParams.eMode == Sink)
                return MFX_ERR_UNSUPPORTED;

            // In case of MVC only MVC-MVC transcoding is supported
            if (InputParams.bIsMVC)
                return MFX_ERR_UNSUPPORTED;

            VAL_CHECK(i+1 == argc, i, argv[i]);
            i++;
            msdk_strcopy(InputParams.strDstFile, argv[i]);
            InputParams.EncodeId = MFX_CODEC_JPEG;
        }
        else if (0 == msdk_strcmp(argv[i], MSDK_STRING("-sw")))
        {
            InputParams.libType = MFX_IMPL_SOFTWARE;
        }
        else if (0 == msdk_strcmp(argv[i], MSDK_STRING("-hw")))
        {
            InputParams.libType = MFX_IMPL_HARDWARE_ANY;
        }        
        else if (0 == msdk_strcmp(argv[i], MSDK_STRING("-hw_d3d11")))
        {
            InputParams.libType = MFX_IMPL_HARDWARE_ANY | MFX_IMPL_VIA_D3D11;
        }
        else if (0 == msdk_strcmp(argv[i], MSDK_STRING("-perf_opt")))
        {
            InputParams.bIsPerf = true;
        }
        else if(0 == msdk_strcmp(argv[i], MSDK_STRING("-f")))
        {
            VAL_CHECK(i+1 == argc, i, argv[i]);
            i++;
            if (1 != msdk_sscanf(argv[i], MSDK_STRING("%lf%c"), &InputParams.dFrameRate, &endC, sizeof (endC)))
            {
                PrintHelp(NULL, MSDK_STRING("frameRate \"%s\" is invalid"), argv[i]);
                return MFX_ERR_UNSUPPORTED;
            }          
        }
        else if(0 == msdk_strcmp(argv[i], MSDK_STRING("-b")))
        {
            VAL_CHECK(i+1 == argc, i, argv[i]);
            i++;
            if (1 != msdk_sscanf(argv[i], MSDK_STRING("%d%c"), &InputParams.nBitRate, &endC, sizeof (endC)))
            {
                PrintHelp(NULL, MSDK_STRING("bitRate \"%s\" is invalid"), argv[i]);
                return MFX_ERR_UNSUPPORTED;
            }
        }
        else if(0 == msdk_strcmp(argv[i], MSDK_STRING("-u")))
        {
            VAL_CHECK(i+1 == argc, i, argv[i]);
            i++;
            if (1 != msdk_sscanf(argv[i], MSDK_STRING("%hd%c"), &InputParams.nTargetUsage, &endC, sizeof (endC)))
            {
                PrintHelp(NULL, MSDK_STRING(" \"%s\" target usage is invalid"), argv[i]);
                return MFX_ERR_UNSUPPORTED;
            }  
        }
        else if(0 == msdk_strcmp(argv[i], MSDK_STRING("-q")))
        {
            VAL_CHECK(i+1 == argc, i, argv[i]);
            i++;
            if (1 != msdk_sscanf(argv[i], MSDK_STRING("%hd%c"), &InputParams.nQuality, &endC, sizeof (endC)))
            {
                PrintHelp(NULL, MSDK_STRING(" \"%s\" quality is invalid"), argv[i]);
                return MFX_ERR_UNSUPPORTED;
            }            
        }        
        else if (0 == msdk_strcmp(argv[i], MSDK_STRING("-w")))
        {
            VAL_CHECK(i+1 == argc, i, argv[i]);
            i++;
            if (1 != msdk_sscanf(argv[i], MSDK_STRING("%hd%c"), &InputParams.nDstWidth, &endC, sizeof (endC)))
            {
                PrintHelp(NULL, MSDK_STRING("width \"%s\" is invalid"), argv[i]);
                return MFX_ERR_UNSUPPORTED;
            }  
        }
        else if (0 == msdk_strcmp(argv[i], MSDK_STRING("-h")))
        {
            VAL_CHECK(i+1 == argc, i, argv[i]);
            i++;
            if (1 != msdk_sscanf(argv[i], MSDK_STRING("%hd%c"), &InputParams.nDstHeight, &endC, sizeof (endC)))
            {
                PrintHelp(NULL, MSDK_STRING("height \"%s\" is invalid"), argv[i]);
                return MFX_ERR_UNSUPPORTED;
            }  
        }        
        else if (0 == msdk_strcmp(argv[i], MSDK_STRING("-l")))
        {
            VAL_CHECK(i+1 == argc, i, argv[i]);
            i++;
            if (1 != msdk_sscanf(argv[i], MSDK_STRING("%hd%c"), &InputParams.nSlices, &endC, sizeof (endC)))
            {
                PrintHelp(NULL, MSDK_STRING("numSlices \"%s\" is invalid"), argv[i]);
                return MFX_ERR_UNSUPPORTED;
            }  
        }
        else if (0 == msdk_strcmp(argv[i], MSDK_STRING("-async")))
        {
            VAL_CHECK(i+1 == argc, i, argv[i]);
            i++;
            if (1 != msdk_sscanf(argv[i], MSDK_STRING("%hd%c"), &InputParams.nAsyncDepth, &endC, sizeof (endC)))
            {
                PrintHelp(NULL, MSDK_STRING("async \"%s\" is invalid"), argv[i]);
                return MFX_ERR_UNSUPPORTED;
            }  
        }
        else if (0 == msdk_strcmp(argv[i], MSDK_STRING("-join")))
        {
           InputParams.bIsJoin = true;
        }
        else if (0 == msdk_strcmp(argv[i], MSDK_STRING("-priority")))
        {
            VAL_CHECK(i+1 == argc, i, argv[i]);
            i++;
            if (1 != msdk_sscanf(argv[i], MSDK_STRING("%hd%c"), &InputParams.priority, &endC, sizeof (endC)))
            {
                PrintHelp(NULL, MSDK_STRING("priority \"%s\" is invalid"), argv[i]);
                return MFX_ERR_UNSUPPORTED;
            }
        }
        else if (0 == msdk_strcmp(argv[i], MSDK_STRING("-i::source")))
        {
            if (InputParams.eMode != Native)
                return MFX_ERR_UNSUPPORTED;


            InputParams.eMode = Source;
        } 
        else if (0 == msdk_strcmp(argv[i], MSDK_STRING("-o::sink")))
        {
             if (InputParams.eMode != Native)
                return MFX_ERR_UNSUPPORTED;


            InputParams.eMode = Sink;

        }        
        else if (0 == msdk_strcmp(argv[i], MSDK_STRING("-n")))
        {
            VAL_CHECK(i+1 == argc, i, argv[i]);
            i++;
            if (1 != msdk_sscanf(argv[i], MSDK_STRING("%d%c"), &InputParams.MaxFrameNumber, &endC, sizeof (endC)))
            {
                PrintHelp(NULL, MSDK_STRING("-n \"%s\" is invalid"), argv[i]);
                return MFX_ERR_UNSUPPORTED;
            }
        }
        else if (0 == msdk_strcmp(argv[i], MSDK_STRING("-angle")))
        {
            VAL_CHECK(i+1 == argc, i, argv[i]);
            i++;
            if (1 != msdk_sscanf(argv[i], MSDK_STRING("%hd%c"), &InputParams.nRotationAngle, &endC, sizeof (endC)))
            {
                PrintHelp(NULL, MSDK_STRING("-angle \"%s\" is invalid"), argv[i]);
                return MFX_ERR_UNSUPPORTED;
            }
            msdk_strcopy(InputParams.strPluginDLLPath, MSDK_STRING("sample_rotate_plugin.dll"));
        }
        else if (0 == msdk_strcmp(argv[i], MSDK_STRING("-opencl")))
        {            
            msdk_strcopy(InputParams.strPluginDLLPath, MSDK_STRING("sample_plugin_opencl.dll"));             
        }
        // output PicStruct
        else if (0 == msdk_strcmp(argv[i], MSDK_STRING("-deinterlace")))
        {
            InputParams.bEnableDeinterlacing = true;
        }
        // skip already parsed global command line options
        else if (0 == msdk_strcmp(argv[i], MSDK_STRING("-par")) || 
            0 == msdk_strcmp(argv[i], MSDK_STRING("-p")))
        {
            skipped += 2;
            i++;
        }
        else if (0 == msdk_strcmp(argv[i], MSDK_STRING("-?")))
        {
            skipped++;
        }
        else
        {
            PrintHelp(NULL, MSDK_STRING("Invalid input argument number %d \"%s\""), i, argv[i]);
            return MFX_ERR_UNSUPPORTED;
        }
    }
    
    if (skipped < argc)
    {
        sts = VerifyAndCorrectInputParams(InputParams);
        MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
        m_SessionArray.push_back(InputParams);
    }

    return MFX_ERR_NONE;

} //mfxStatus CmdProcessor::ParseParamsForOneSession(msdk_char *pLine, mfxU32 length)

mfxStatus CmdProcessor::VerifyAndCorrectInputParams(TranscodingSample::sInputParams &InputParams)
{
    if (0 == msdk_strlen(InputParams.strSrcFile) && (InputParams.eMode == Sink || InputParams.eMode == Native))
    {
        PrintHelp(NULL, MSDK_STRING("Source file name not found"));
        return MFX_ERR_UNSUPPORTED;
    };

    if (0 == msdk_strlen(InputParams.strDstFile) && (InputParams.eMode == Source || InputParams.eMode == Native))
    {
        PrintHelp(NULL, MSDK_STRING("Destination file name not found"));
        return MFX_ERR_UNSUPPORTED;
    };

    if (MFX_CODEC_JPEG != InputParams.EncodeId && MFX_CODEC_MPEG2 != InputParams.EncodeId && MFX_CODEC_AVC != InputParams.EncodeId && InputParams.eMode != Sink)
    {
        PrintHelp(NULL, MSDK_STRING("Unknown encoder\n"));
        return MFX_ERR_UNSUPPORTED;
    }

    if (MFX_CODEC_MPEG2 != InputParams.DecodeId &&
       MFX_CODEC_AVC != InputParams.DecodeId && 
       MFX_CODEC_VC1 != InputParams.DecodeId && 
       MFX_CODEC_JPEG != InputParams.DecodeId &&
       InputParams.eMode != Source)
    {
        PrintHelp(NULL, MSDK_STRING("Unknown decoder\n"));
        return MFX_ERR_UNSUPPORTED;
    }

    if (InputParams.nQuality && InputParams.EncodeId && (MFX_CODEC_JPEG != InputParams.EncodeId))
    {
        PrintHelp(NULL, MSDK_STRING("-q option is supported only for JPEG encoder\n"));
        return MFX_ERR_UNSUPPORTED;
    }

    if ((InputParams.nTargetUsage || InputParams.nBitRate) && (MFX_CODEC_JPEG == InputParams.EncodeId))
    {
        PrintHelp(NULL, MSDK_STRING("-b and -u options are supported only for H.264, MPEG2 and MVC encoders. For JPEG encoder use -q\n"));
        return MFX_ERR_UNSUPPORTED;
    }

    // set default values for optional parameters that were not set or were set incorrectly   
    if (MFX_TARGETUSAGE_BEST_QUALITY != InputParams.nTargetUsage && MFX_TARGETUSAGE_BEST_SPEED != InputParams.nTargetUsage)
    {
        InputParams.nTargetUsage = MFX_TARGETUSAGE_BALANCED;
    }

    // Sample does not support user plugin with '-hw_d3d11'
    if ((InputParams.libType & MFX_IMPL_VIA_D3D11) && InputParams.nRotationAngle != 0)
    {
        PrintHelp(NULL, MSDK_STRING("Sample does not support user plugin with '-hw_d3d11'\n"));
        return MFX_ERR_UNSUPPORTED;
    }


    return MFX_ERR_NONE;

} //mfxStatus CmdProcessor::VerifyAndCorrectInputParams(TranscodingSample::sInputParams &InputParams)

bool  CmdProcessor::GetNextSessionParams(TranscodingSample::sInputParams &InputParams)
{
    if (!m_SessionArray.size())
        return false;
    if (m_SessionParamId == m_SessionArray.size())
    {
        return false;
    }
    InputParams = m_SessionArray[m_SessionParamId];
    m_SessionParamId++;
    return true;

} //bool  CmdProcessor::GetNextSessionParams(TranscodingSample::sInputParams &InputParams)

// Wrapper on standard allocator for concurrent allocation of 
// D3D and system surfaces
GeneralAllocator::GeneralAllocator() 
{
   
};
GeneralAllocator::~GeneralAllocator() 
{
};
mfxStatus GeneralAllocator::Init(mfxAllocatorParams *pParams)
{
    mfxStatus sts = MFX_ERR_NONE;
#if MFX_D3D11_SUPPORT
    D3D11AllocatorParams *d3d11AllocParams = dynamic_cast<D3D11AllocatorParams*>(pParams);
    if (d3d11AllocParams)
    {
        m_D3DAllocator.reset(new D3D11FrameAllocator);

    }
    else
#endif
    {
        m_D3DAllocator.reset(new D3DFrameAllocator);
    }

    m_SYSAllocator.reset(new SysMemFrameAllocator);

    sts = m_D3DAllocator.get()->Init(pParams);
    MSDK_CHECK_RESULT(MFX_ERR_NONE, sts, sts);

    sts = m_SYSAllocator.get()->Init(0);
    MSDK_CHECK_RESULT(MFX_ERR_NONE, sts, sts);

    return sts;
}
mfxStatus GeneralAllocator::Close()
{
    mfxStatus sts = MFX_ERR_NONE;
    sts = m_D3DAllocator.get()->Close();
    MSDK_CHECK_RESULT(MFX_ERR_NONE, sts, sts);

    sts = m_SYSAllocator.get()->Close();
    MSDK_CHECK_RESULT(MFX_ERR_NONE, sts, sts);

   return sts;
}

mfxStatus GeneralAllocator::LockFrame(mfxMemId mid, mfxFrameData *ptr)
{
    return isD3DMid(mid)?m_D3DAllocator.get()->Lock(m_D3DAllocator.get(), mid, ptr):
                         m_SYSAllocator.get()->Lock(m_SYSAllocator.get(),mid, ptr);
}
mfxStatus GeneralAllocator::UnlockFrame(mfxMemId mid, mfxFrameData *ptr)
{
    return isD3DMid(mid)?m_D3DAllocator.get()->Unlock(m_D3DAllocator.get(), mid, ptr):
                         m_SYSAllocator.get()->Unlock(m_SYSAllocator.get(),mid, ptr);
}

mfxStatus GeneralAllocator::GetFrameHDL(mfxMemId mid, mfxHDL *handle)
{
    return isD3DMid(mid)?m_D3DAllocator.get()->GetHDL(m_D3DAllocator.get(), mid, handle):
                         m_SYSAllocator.get()->GetHDL(m_SYSAllocator.get(), mid, handle);
}

mfxStatus GeneralAllocator::ReleaseResponse(mfxFrameAllocResponse *response)
{
    // try to ReleaseResponse via D3D allocator
    return isD3DMid(response->mids[0])?m_D3DAllocator.get()->Free(m_D3DAllocator.get(),response):
                                       m_SYSAllocator.get()->Free(m_SYSAllocator.get(), response);
}
mfxStatus GeneralAllocator::AllocImpl(mfxFrameAllocRequest *request, mfxFrameAllocResponse *response)
{
    mfxStatus sts;
    if (request->Type & MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET || request->Type & MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET)
    {
        sts = m_D3DAllocator.get()->Alloc(m_D3DAllocator.get(), request, response);
        StoreFrameMids(true, response);
    }
    else
    {
        sts = m_SYSAllocator.get()->Alloc(m_SYSAllocator.get(), request, response);
        StoreFrameMids(false, response);
    }
    return sts;
}
void    GeneralAllocator::StoreFrameMids(bool isD3DFrames, mfxFrameAllocResponse *response)
{
    for (mfxU32 i = 0; i < response->NumFrameActual; i++)
        m_Mids.insert(std::pair<mfxHDL, bool>(response->mids[i], isD3DFrames));
}
bool GeneralAllocator::isD3DMid(mfxHDL mid)
{
    std::map<mfxHDL, bool>::iterator it;
    it = m_Mids.find(mid);
    if (it == m_Mids.end())
        return false; // sys mem allocator will check validity of mid further
    else
        return it->second;
}
